package pers.ree.demo.concurrent;

import java.util.concurrent.TimeUnit;

/**
 * 验证用String对象作为锁的几种情况：
 * 1.无论直接用字面量如"123"还是用指向字面量的变量如示例的lock1（lock1 = "123"），
 * 哪怕是多个同步块，主要用的是同个字面量，使用的都是同一把锁；
 * 2.如果使用的是new的String对象，即使值与字符串字面量相同，如loc2（lock2 = new String("123")），
 * 或者直接在synchronized中new一个字面量相同的String对象，如print8（synchronized(new String("123"))）
 * 也不是同一把锁；
 */
public class StringLockDemo {

    private static final String lock3 = "123";
    private static final String lock4 = lock3;
    private static final String lock5 = new String("123");
    private static final String lock6 = lock5;
    private static final String lock7 = new String("123");

    private static int i = 0;

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                increment();
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                increment();
            }
        });

        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                print1();
            }
        });

        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                print1_1();
            }
        });

        Thread t5 = new Thread(new Runnable() {
            @Override
            public void run() {
                print3();
            }
        });

        Thread t6 = new Thread(new Runnable() {
            @Override
            public void run() {
                print4();
            }
        });

        Thread t7 = new Thread(new Runnable() {
            @Override
            public void run() {
                print5();
            }
        });

        Thread t8 = new Thread(new Runnable() {
            @Override
            public void run() {
                print6();
            }
        });

        Thread t9 = new Thread(new Runnable() {
            @Override
            public void run() {
                print7();
            }
        });

        Thread t10 = new Thread(new Runnable() {
            @Override
            public void run() {
                print8();
            }
        });

        t1.setName("t1_increment1");
        t1.start();

        t2.setName("t2_increment2");
        t2.start();

        t3.setName("t3_print1");
        t3.start();

        t4.setName("t4_print1_1");
        t4.start();

        t5.setName("t5_print3");
        t5.start();

        t6.setName("t6_print4");
        t6.start();

        t7.setName("t7_print5");
        t7.start();

        t8.setName("t8_print6");
        t8.start();

        t9.setName("t9_print7");
        t9.start();

        t10.setName("t10_print8");
        t10.start();
    }

    public static void increment() {
        synchronized ("123") {
            i++;
            System.out.println(Thread.currentThread().getName() + ", " + i + ", " + System.currentTimeMillis());
            try {
                TimeUnit.MILLISECONDS.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ", run end, " + System.currentTimeMillis());
        }
    }

    public static void print1() {
        synchronized ("123") {
            doPrint();
        }
    }

    public static void print1_1() {
        synchronized ("123") {
            doPrint();
        }
    }

    public static void print3() {
        synchronized (lock3) {
            doPrint();
        }
    }

    public static void print4() {
        synchronized (lock4) {
            doPrint();
        }
    }

    public static void print5() {
        synchronized (lock5) {
            doPrint();
        }
    }

    public static void print6() {
        synchronized (lock6) {
            doPrint();
        }
    }

    public static void print7() {
        synchronized (lock7) {
            doPrint();
        }
    }

    public static void print8() {
        synchronized (new String("123")) {
            doPrint();
        }
    }


    public static void doPrint() {
        System.out.println(Thread.currentThread().getName() + ", " + System.currentTimeMillis());
        try {
            TimeUnit.MILLISECONDS.sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ", run end, " + System.currentTimeMillis());
    }
}
